﻿using CatUtils.Utils.Currency;
using CatUtils.Utils.Currency.TextUtils;
using CatUtilsDll.Utils.Currency.WebUtils;
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using static CatUtilsDll.Utils.Currency.WebUtils.WebHelper;

namespace CatUtils.Utils.SpecialUtils.Html
{/// <summary>
/// html帮助 基于 HtmlAgilityPack
/// </summary>
    public partial class HtmlHelper
    {
        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static bool delScriptSetting = true;

        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static bool delStyleSetting = true;

        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static bool delCommentSetting = true;

        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static bool delIframeSetting = true;

        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static bool delInvalidImgSetting = false;

        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static bool delEmptyLableSetting = true;

        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static bool delAllAttributesSetting = false;

        /// <summary>
        /// 最终发布时清理文章内容的补丁
        /// </summary>
        private static List<string> writeAttributes = new List<string> { "src", "href" };

        /// <summary>
        /// 删除Javascritp的设置 默认为true
        /// </summary>
        public static bool DelScriptSetting { get => delScriptSetting; set => delScriptSetting = value; }

        /// <summary>
        /// 删除CSS的设置 默认为true
        /// </summary>
        public static bool DelStyleSetting { get => delStyleSetting; set => delStyleSetting = value; }

        /// <summary>
        /// 删除Html文本注释的设置 默认为true
        /// </summary>
        public static bool DelCommentSetting { get => delCommentSetting; set => delCommentSetting = value; }

        /// <summary>
        /// 删除Iframer的设置 默认为true
        /// </summary>
        public static bool DelIframeSetting { get => delIframeSetting; set => delIframeSetting = value; }

        /// <summary>
        /// 删除失效图片的设置，会检查图片有效性，默认为false
        /// </summary>
        public static bool DelInvalidImgSetting { get => delInvalidImgSetting; set => delInvalidImgSetting = value; }

        /// <summary>
        /// 删除空标签的设置，默认为true
        /// </summary>
        public static bool DelEmptyLableSetting { get => delEmptyLableSetting; set => delEmptyLableSetting = value; }

        /// <summary>
        /// 删除标签内无用标签，默认为false, 启用后请设置参数WriteAttributesSetting，将标签列入白名单
        /// </summary>
        public static bool DelAllAttributesSetting { get => delAllAttributesSetting; set => delAllAttributesSetting = value; }

        /// <summary>
        ///DelAllAttributesSetting设置后生效，默认跳过Attributes： "src", "href"
        /// </summary>
        public static List<string> WriteAttributesSetting { get => writeAttributes; set => writeAttributes = value; }

        /// <summary>
        /// 加载HTML
        /// </summary>
        /// <param name="Htmlnode"></param>
        /// <returns></returns>
        public static HtmlDocument LoadHtml(string Htmlnode)
        {
            HtmlDocument doc = new HtmlDocument();
            try
            {
                if (Htmlnode != null && Htmlnode != "")
                    doc.LoadHtml(Htmlnode);
                else
                    doc.LoadHtml("");
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
                PrintLog.Log("加载HTML错误 ");
            }
            return doc;
        }

        /// <summary>
        /// 删除常见的不安全代码 请注意，参数受htmlhelper.(DelScriptSetting, DelScriptSetting, DelScriptSetting, DelInvalidImgSetting)影响
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <returns></returns>
        public static string RemoveUnsafe(string HtmlCode)
        {
            return RemoveUnsafe(HtmlCode, DelScriptSetting, DelScriptSetting, DelScriptSetting, DelInvalidImgSetting);
        }

        /// <summary>
        /// 删除常见的不安全代码
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="DelScript">删除JS脚本</param>
        /// <param name="DelStyle">删除样式文件</param>
        /// <param name="DelComment">删除注释</param>
        /// <param name="DelIframe">删除框架</param>
        /// <returns></returns>
        public static string RemoveUnsafe(string HtmlCode, bool DelScript, bool DelStyle, bool DelComment, bool DelIframe)
        {
            if (DelScript)
                HtmlCode = RemoveNode(HtmlCode, "//script");
            if (DelStyle)
                HtmlCode = RemoveNode(HtmlCode, "//style");
            if (DelComment)
                HtmlCode = RemoveNode(HtmlCode, "//comment()");
            if (DelIframe)
                HtmlCode = RemoveNode(HtmlCode, "//iframe");
            return ReomveEmptyLine(HtmlCode);
        }

        /// <summary>
        ///  删除失效图片 通过下载文件，如果下载不成功则删除
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="blockImgs"></param>
        /// <returns></returns>
        public static string RemoveInvalidImgByDownload(string HtmlCode, string Xpath, List<BlockImgInfo> blockImgs)
        {
            var htmlDoc = LoadHtml(HtmlCode);

            try
            {
                HtmlNodeCollection htmlNodes = SelectNodes(htmlDoc, Xpath);
                if (htmlNodes != null)
                    foreach (var item in htmlNodes)
                    {
                        string ImgLink = GetAttributesVlaue(item, "src");
                        string TempImgLink = ImgLink;
                        bool NoneProtocol = false;
                        if (TempImgLink == "")
                        {
                            item.Remove();
                            continue;
                        }
                        if (ImgLink.IndexOf("//") == 0)
                        {
                            TempImgLink = "http:" + ImgLink;
                            NoneProtocol = true;
                        }

                        if (!CheckImgExits(TempImgLink, blockImgs))
                        {
                            item.Remove();
                        }
                        if (NoneProtocol)
                        {
                            TempImgLink = "https:" + ImgLink;
                            if (!CheckImgExits(TempImgLink, blockImgs))
                            {
                                item.Remove();
                            }
                        }
                    }
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }

            return ReomveEmptyLine(htmlDoc.DocumentNode.InnerHtml);
        }

        /// <summary>
        ///  删除失效图片 通过下载文件，如果下载不成功则删除
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string RemoveInvalidImgByDownload(string HtmlCode, string Xpath)
        {
            return RemoveInvalidImgByDownload(HtmlCode, Xpath, new List<BlockImgInfo> { new BlockImgInfo { FileSize = 0, ImgWidth = 0, ImgHeight = 0 } });
        }

        /// <summary>
        /// 删除失效图片  通过请求返回码
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <returns></returns>
        public static string RemoveInvalidImg(string HtmlCode)
        {
            return RemoveInvalidImg(HtmlCode, "//img", WriteAttributesSetting, true);
        }

        /// <summary>
        /// 删除失效图片 通过请求返回码
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="WriteList"></param>
        /// <param name="RemoveOtherAttributes">是否仅保留Src，删除其他属性</param>
        /// <returns></returns>
        public static string RemoveInvalidImg(string HtmlCode, string Xpath, List<string> WriteList, bool RemoveOtherAttributes)
        {
            var htmlDoc = LoadHtml(HtmlCode);
            try
            {
                HtmlNodeCollection htmlNodes = SelectNodes(htmlDoc, Xpath);
                if (htmlNodes != null)
                    foreach (var item in htmlNodes)
                    {
                        string ImgLink = GetAttributesVlaue(item, "src");
                        string TempImgLink = ImgLink;
                        bool NoneProtocol = false;

                        if (ListHelper.CompareRepetition(ImgLink, WriteList, false))
                            continue;
                        if (TempImgLink == "")
                        {
                            item.Remove();
                            continue;
                        }
                        if (ImgLink.IndexOf("//") == 0)
                        {
                            TempImgLink = "http:" + ImgLink;
                            NoneProtocol = true;
                        }

                        if (new WebHelper().GetStatusMove(TempImgLink, new List<string> { "404", "超时", "500" }))
                        {
                            item.Remove();
                            continue;
                        }
                        if (NoneProtocol)
                        {
                            TempImgLink = "https:" + ImgLink;
                            if (new WebHelper().GetStatusMove(TempImgLink, new List<string> { "404", "超时", "500" }))
                            {
                                item.Remove();
                                continue;
                            }
                        }

                        if (RemoveOtherAttributes)
                        {
                            RemoveAllAttributes(item);//删除所有属性
                            item.Attributes.Add("src", ImgLink);//重新填加回SRC
                        }
                    }
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }

            return ReomveEmptyLine(htmlDoc.DocumentNode.InnerHtml);
        }

        /// <summary>
        /// 将A标签转换为纯Text
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <returns></returns>
        public static string ReplaceLableAOnlyText(string HtmlCode)
        {
            return ReplaceLableAOnlyText(HtmlCode, "//a");
        }

        /// <summary>
        /// 将A标签转换为纯Text
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        public static string ReplaceLableAOnlyText(string HtmlCode, string Xpath)
        {
            var HtmlDoc = LoadHtml(HtmlCode);
            try
            {
                HtmlNodeCollection htmlNodes = SelectNodes(HtmlDoc, Xpath);
                if (htmlNodes != null)
                    foreach (var item in htmlNodes)
                    {
                        Console.WriteLine(HtmlCodeCreate.LableA(item.InnerText));
                        item.ParentNode.InsertAfter(HtmlNode.CreateNode(HtmlCodeCreate.LableA(item.InnerText)), item);
                        item.Remove();
                    }
            }
            catch (Exception ex) { PrintLog.E(ex.Message); }

            return InnHtml(HtmlDoc);
        }

        /// <summary>
        /// 删除A标签的链接
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="RemoveOtherAttributes">是否仅保留链接，删除其他属性</param>
        /// <returns></returns>
        public static string RemoveLink(string HtmlCode, string Xpath, bool RemoveOtherAttributes)
        {
            return RemoveLink(HtmlCode, Xpath, new List<string>(), RemoveOtherAttributes);
        }

        /// <summary>
        /// 删除A标签的链接
        /// </summary>
        /// <param name="HtmlCode"></param>

        public static string RemoveLink(string HtmlCode)
        {
            return RemoveLink(HtmlCode, "//a", new List<string>(), true);
        }

        /// <summary>
        /// 删除A标签的链接
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        public static string RemoveLink(string HtmlCode, string Xpath)
        {
            return RemoveLink(HtmlCode, Xpath, new List<string>(), true);
        }

        /// <summary>
        ///     删除A标签的链接
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="WriteList"></param>
        /// <param name="RemoveOtherAttributes">是否仅保留链接，删除其他属性</param>
        /// <returns></returns>
        public static string RemoveLink(string HtmlCode, string Xpath, List<string> WriteList, bool RemoveOtherAttributes)
        {
            var HtmlDoc = LoadHtml(HtmlCode);
            try
            {
                HtmlNodeCollection htmlNodes = SelectNodes(HtmlDoc, Xpath);
                if (htmlNodes != null)
                    foreach (var item in htmlNodes)
                    {
                        string Link = GetAttributesVlaue(item, "href");
                        if (Link == "")
                        {
                            if (RemoveOtherAttributes)
                                RemoveAllAttributes(item);
                            else
                                continue;
                        }

                        if (RemoveOtherAttributes)
                        {
                            RemoveAllAttributes(item);
                            item.Attributes.Add("href", Link);
                        }

                        if (ListHelper.CompareRepetition(Link, WriteList))
                        {
                            continue;
                        }
                        AttributesRemove(item, "href");
                    }
            }
            catch (Exception ex) { PrintLog.E(ex); }
            return ReomveEmptyLine(InnHtml(HtmlDoc));
        }

        /// <summary>
        /// 清理删除HTML节点导致的空行
        /// </summary>
        /// <param name="InnHtml"></param>
        /// <returns></returns>
        private static string ReomveEmptyLine(string InnHtml)
        {
            return TextHelper.ReplaceTextEnhance(InnHtml, @"\s{0,}[\r\n]{2,}", "\n", RegexOptions.Multiline);
        }

        /// <summary>
        /// 删除子项，但是保留孙项目
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string RemoveChildern(string HtmlCode, string Xpath)
        {
            return RemoveChildern(HtmlCode, Xpath, true);
        }

        /// <summary>
        /// 删除子项 如果需要保留内容，则设定KeepGrandChildren
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="XpathList"></param>
        /// <param name="KeepGrandChildren"></param>
        /// <returns></returns>
        public static string RemoveChildern(string HtmlCode, List<string> XpathList, bool KeepGrandChildren)
        {
            foreach (var item in XpathList)
            {
                HtmlCode = RemoveChildern(HtmlCode, item, KeepGrandChildren);
            }
            return HtmlCode;
        }

        /// <summary>
        /// 获取HtmlNode 如果没有获取到返回NULL
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static HtmlNodeCollection GetHtmlNodes(string HtmlCode, string Xpath)
        {
            return SelectNodes(HtmlCode, Xpath);
        }

        /// <summary>
        /// 获取HtmlNode 如果没有获取到返回NULL
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static HtmlNode GetFirstHtmlNode(string HtmlCode, string Xpath)
        {
            HtmlNodeCollection htmlNodes = SelectNodes(HtmlCode, Xpath);
            if (htmlNodes == null)
                return null;
            return htmlNodes.FirstOrDefault();
        }

        /// <summary>
        ///  删除子项 如果需要保留内容，则设定KeepGrandChildren
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="KeepGrandChildren">删除子项，选择是否保留孙项</param>
        /// <returns></returns>
        public static string RemoveChildern(string HtmlCode, string Xpath, bool KeepGrandChildren)
        {
            var HtmlDoc = LoadHtml(HtmlCode);
            try
            {
                HtmlNodeCollection htmlNodes = SelectNodes(HtmlDoc, Xpath);
                if (htmlNodes != null)
                    foreach (HtmlNode comment in htmlNodes)
                    {
                        comment.ParentNode.RemoveChild(comment, KeepGrandChildren);
                    }
            }
            catch (Exception ex)
            {
                PrintLog.E(ex);
            }
            return ReomveEmptyLine(InnHtml(HtmlDoc));
        }

        /// <summary>
        /// 删除所有Attributes
        /// </summary>
        /// <param name="htmlNode"></param>
        public static void RemoveAllAttributes(HtmlNode htmlNode)
        {
            try
            {
                if (htmlNode == null || htmlNode.Attributes == null)
                    return;
                htmlNode.Attributes.RemoveAll();
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
        }

        /// <summary>
        /// 删除全部第三方属性 如果有想跳过的请设置白名单  默认使用htmlhelper.WriteAttributesSetting
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <returns></returns>
        public static string RemoveAllAttributes(string HtmlCode)
        {
            return RemoveAllAttributes(HtmlCode, WriteAttributesSetting, "");
        }

        /// <summary>
        ///   删除全部第三方属性 如果有想跳过的请设置白名单  默认使用htmlhelper.WriteAttributesSetting
        /// </summary>

        /// <param name="HtmlCode"></param>
        /// <param name="Xpath">如果留空，则对所有标签进行遍历过滤</param>
        /// <returns></returns>
        public static string RemoveAllAttributes(string HtmlCode, string Xpath)
        {
            return RemoveAllAttributes(HtmlCode, WriteAttributesSetting, Xpath);
        }

        /// <summary>
        /// 删除全部第三方属性 如果有想跳过的请设置白名单
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="WriteAttributes"></param>
        /// <returns></returns>
        public static string RemoveAllAttributes(string HtmlCode, List<string> WriteAttributes)
        {
            return RemoveAllAttributes(HtmlCode, WriteAttributes, "");
        }

        /// <summary>
        ///  删除全部第三方属性 如果有想跳过的请设置白名单
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="WriteAttributes">白名单关键词</param>
        /// <param name="Xpath">如果留空，则对所有标签进行遍历过滤</param>
        /// <returns></returns>
        public static string RemoveAllAttributes(string HtmlCode, List<string> WriteAttributes, string Xpath)
        {
            var HtmlDoc = LoadHtml(HtmlCode);

            HtmlNode[] SelectNode = null;
            if (Xpath != "")
            {
                var htmlNodes = SelectNodes(HtmlDoc, Xpath);
                if (htmlNodes != null)
                    SelectNode = htmlNodes.ToArray();
            }
            else
            {
                SelectNode = HtmlDoc.DocumentNode.Descendants().ToArray();
            }

            if (SelectNode != null)
            {
                foreach (var Item in SelectNode)
                {
                    try
                    {
                        if (Item.Attributes == null)
                            continue;
                        if (WriteAttributes.Count != 0)
                        {
                            foreach (var Attribute in Item.Attributes.ToList())
                            {
                                if (!ListHelper.EqualsList(Attribute.Name, WriteAttributes, false))

                                    AttributesRemove(Item, Attribute.Name);
                            }
                        }
                        else
                        {
                            Item.Attributes.Remove();
                        }
                    }
                    catch (Exception ex)
                    {
                        PrintLog.Log(ex);
                    }
                }
            }
            return InnHtml(HtmlDoc);
        }

        /// <summary>
        /// 清理项目代码
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <returns></returns>
        public static string ClearHtml(string HtmlCode)
        {
            return ClearHtml(HtmlCode, true, true, true, true, true, true, true, new List<string> { "href", "src" });
        }

        /// <summary>
        /// 清理所选项的代码
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="DelScript">删除JS脚本</param>
        /// <param name="DelStyle">删除样式文件</param>
        /// <param name="DelComment">删除注释</param>
        /// <param name="DelIframe">删除框架</param>
        /// <param name="DelInvalidImg">删除失效的不正常图片，注意：相对地址图片也会被删除，请自行处理</param>
        /// <param name="DelEmptyLable">删除空标签</param>
        /// <param name="DelAllAttributes">删除所有标签属性，但是可以通过WriteAttributes设置需要跳过的属性</param>
        /// <param name="WriteAttributes">DelAllAttributes为True时，设置需要跳过的白名单属性。</param>
        /// <returns></returns>
        public static string ClearHtml(string HtmlCode, bool DelScript, bool DelStyle, bool DelComment, bool DelIframe,
            bool DelInvalidImg, bool DelEmptyLable, bool DelAllAttributes,
         List<string> WriteAttributes)
        {
            HtmlCode = RemoveUnsafe(HtmlCode, DelScript, DelStyle, DelComment, DelIframe);
            if (DelInvalidImg)
                HtmlCode = RemoveInvalidImg(HtmlCode);
            if (DelEmptyLable)
                HtmlCode = RemoveEmptyLable(HtmlCode);
            if (DelAllAttributes)
                HtmlCode = RemoveAllAttributes(HtmlCode, WriteAttributes);
            return HtmlCode;
        }

        /// <summary>
        /// 删除空标签
        /// </summary>
        /// <param name="Content"></param>
        /// <returns></returns>
        public static string RemoveEmptyLable(string Content)
        {
            var HtmlDoc = LoadHtml(Content);
            if (HtmlDoc == null)
                return "";
            RemoveEmptyLable(HtmlDoc.DocumentNode);
            return ReomveEmptyLine(InnHtml(HtmlDoc));
        }

        /// <summary>
        /// 删除空标签
        /// </summary>
        /// <param name="containerNode"></param>
        /// <returns></returns>
        public static string RemoveEmptyLable(HtmlNode containerNode)
        {
            List<string> _notToRemove = new List<string>() { "br", "#comment" };

            if (containerNode.Attributes.Count == 0 && !_notToRemove.Contains(containerNode.Name)
                && string.IsNullOrEmpty(containerNode.InnerText) && containerNode.ChildNodes.Count == 0)
            {
                containerNode.Remove();
            }
            else
            {
                for (int i = containerNode.ChildNodes.Count - 1; i >= 0; i--)
                {
                    RemoveEmptyLable(containerNode.ChildNodes[i]);
                }
            }

            return "";
        }

        /// <summary>
        /// 更改Attributes的属性
        /// </summary>
        /// <param name="HtmlCode">Html代码</param>
        /// <param name="Xpath">Xpath属性</param>
        /// <param name="AttributesName">Attributes名字</param>
        /// <param name="NewValue">新的Attributes Value</param>
        /// <returns>返回修改后的Html代码</returns>
        public static string ChangeAttributesValue(string HtmlCode, string Xpath, string AttributesName, string NewValue)
        {
            var HtmlDoc = HtmlHelper.LoadHtml(HtmlCode);
            var elementsWithStyleAttribute = SelectNodes(HtmlDoc, Xpath);

            if (elementsWithStyleAttribute != null)
            {
                foreach (var element in elementsWithStyleAttribute)
                {
                    try
                    {
                        if (element.Attributes[AttributesName] != null)
                            element.Attributes[AttributesName].Value = NewValue;
                    }
                    catch (Exception ex)
                    {
                        PrintLog.Log(ex);
                    }
                }
            }

            return InnHtml(HtmlDoc);
        }

        /// <summary>
        ///  修改Html的Text属性 如<p>Text</p>→<p>New Text</p>
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="NewText"></param>
        /// <returns></returns>
        public static string ChangeText(string HtmlCode, string Xpath, string NewText)
        {
            return ChangeText(HtmlCode, Xpath, NewText, true);
        }

        /// <summary>
        ///  修改Html的Text属性 如<p>Text</p>→<p>New Text</p>
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="NewText"></param>
        /// <param name="XpathCompletion">为True时，不需要在Xpath里写//text()，程序自动在尾部添加</param>
        /// <returns></returns>
        public static string ChangeText(string HtmlCode, string Xpath, string NewText, bool XpathCompletion)
        {
            if (XpathCompletion)
                Xpath += "//text()";
            var HtmlDoc = LoadHtml(HtmlCode);

            var elementsWithStyleAttribute = SelectNodes(HtmlDoc, Xpath);

            if (elementsWithStyleAttribute != null)
            {
                foreach (var element in elementsWithStyleAttribute)
                {
                    try
                    {
                        HtmlTextNode htmlText = element as HtmlTextNode;
                        if (htmlText != null)
                            htmlText.Text = NewText;
                    }
                    catch (Exception ex)
                    {
                        PrintLog.Log(ex);
                    }
                }
            }

            return InnHtml(HtmlDoc);
        }

        /// <summary>
        /// 删除Attribus
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="Attribus"></param>
        /// <returns></returns>
        public static string RemoveAttributes(string HtmlCode, string Xpath, string Attribus)
        {
            var HtmlDoc = LoadHtml(HtmlCode);
            var elementsWithStyleAttribute = SelectNodes(HtmlDoc, Xpath);

            if (elementsWithStyleAttribute != null)
            {
                foreach (var element in elementsWithStyleAttribute)
                {
                    try
                    {
                        AttributesRemove(element, Attribus);
                    }
                    catch (Exception ex)
                    {
                        PrintLog.Log(ex);
                    }
                }
            }
            return ReomveEmptyLine(InnHtml(HtmlDoc));
        }

        /// <summary>
        /// 删除指定位置的代码并且返回string结果
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string RemoveNode(string HtmlCode, string Xpath)
        {
            var HtmlDoc = LoadHtml(HtmlCode);
            var divs = SelectNodes(HtmlDoc, Xpath);

            if (divs != null)
            {
                foreach (var tag in divs)
                {
                    tag.Remove();
                }
            }

            return ReomveEmptyLine(InnHtml(HtmlDoc));
        }

        /// <summary>
        /// 数据鉴别时防止代码污染，返回纯文字
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <returns></returns>
        public static string OutText(string HtmlCode)
        {
            var HtmlDoc = LoadHtml(HtmlCode);
            return InnText(HtmlDoc);
        }

        /// <summary>
        /// 选择HtmlNode并且返回HtmlNodeCollection 如果没有值则返回NULL
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static HtmlNodeCollection SelectNodes(string HtmlCode, string Xpath)
        {
            return SelectNodes(LoadHtml(HtmlCode), Xpath);
        }

        /// <summary>
        ///  选择HtmlNode并且返回HtmlNodeCollection 如果没有值则返回NULL
        /// </summary>
        /// <param name="HtmlDoc"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static HtmlNodeCollection SelectNodes(HtmlDocument HtmlDoc, string Xpath)
        {
            HtmlNodeCollection NodeCollectionvalue = null;
            try
            {
                if (Xpath == "")
                    return NodeCollectionvalue;
                NodeCollectionvalue = HtmlDoc.DocumentNode.SelectNodes(Xpath);
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
                PrintLog.Log($"选择器错误,选择器为：{Xpath}");
            }
            return NodeCollectionvalue;
        }

        /// <summary>
        ///获取选择对象的所有代码  包括对象本身
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static List<string> GetHtmlValueList(string HtmlCode, string Xpath)
        {
            List<string> ValueList = new List<string>();
            HtmlNodeCollection htmlNodeCollection = SelectNodes(HtmlCode, Xpath);
            if (htmlNodeCollection != null)

                foreach (HtmlNode SingleNode in htmlNodeCollection)
                {
                    ValueList.Add(SingleNode.OuterHtml);
                }
            return ValueList;
        }

        /// <summary>
        /// 获取第一个连接结果
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string GetFirstHtml(string HtmlCode, string Xpath)
        {
            return ListHelper.GetFirst(GetHtmlValueList(HtmlCode, Xpath));
        }

        /// <summary>
        /// 获取htmlNodeCollection里的inntext值
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static List<string> GetTextValueList(string HtmlCode, string Xpath)
        {
            List<string> ValueList = new List<string>();
            HtmlNodeCollection htmlNodeCollection = SelectNodes(HtmlCode, Xpath);
            if (htmlNodeCollection != null)

                foreach (HtmlNode SingleNode in htmlNodeCollection)
                {
                    ValueList.Add(SingleNode.InnerText);
                }
            return ValueList;
        }

        /// <summary>
        /// 获取第一个连接结果
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string GetFirstText(string HtmlCode, string Xpath)
        {
            return ListHelper.GetFirst(GetTextValueList(HtmlCode, Xpath));
        }

        /// <summary>
        /// 获取A标签里的href属性值
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static List<string> GetLinkVlaueList(string HtmlCode, string Xpath)
        {
            return GetAttributesVlaueList(HtmlCode, "href", Xpath);
        }

        /// <summary>
        /// 获取图片src的辅助方法
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>

        public static List<string> GetImgSrcVlaueList(string HtmlCode, string Xpath)
        {
            return GetAttributesVlaueList(HtmlCode, "src", Xpath);
        }

        /// <summary>
        /// 获取第一个连接结果
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string GetFirstLink(string HtmlCode, string Xpath)
        {
            return ListHelper.GetFirst(GetLinkVlaueList(HtmlCode, Xpath));
        }

        /// <summary>
        /// 获取第一个图片结果
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string GetFirstSrc(string HtmlCode, string Xpath)
        {
            return ListHelper.GetFirst(GetImgSrcVlaueList(HtmlCode, Xpath));
        }

        /// <summary>
        /// 获取第一个Attributes结果
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Attributes"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static string GetFirstAttributes(string HtmlCode, string Attributes, string Xpath)
        {
            return ListHelper.GetFirst(GetAttributesVlaueList(HtmlCode, Attributes, Xpath));
        }

        /// <summary>
        /// 替换Html节点
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="Xpath"></param>
        /// <param name="NewNode"></param>
        /// <returns></returns>
        public static string ReplaceNode(string HtmlCode, string Xpath, HtmlNode NewNode)
        {
            return ReplaceNode(LoadHtml(HtmlCode), Xpath, NewNode);
        }

        /// <summary>
        /// 替换Html节点
        /// </summary>
        /// <param name="HtmlDoc"></param>
        /// <param name="Xpath">需要替换节点的路径</param>
        /// <param name="NewNode"></param>
        /// <returns></returns>
        public static string ReplaceNode(HtmlDocument HtmlDoc, string Xpath, HtmlNode NewNode)
        {
            try
            {
                if (Xpath == "" || NewNode == null)
                    return InnHtml(HtmlDoc);
                HtmlNodeCollection htmlNodes = SelectNodes(HtmlDoc, Xpath);
                if (htmlNodes != null)
                    foreach (var item in htmlNodes)
                    {
                        ReplaceNode(HtmlDoc, NewNode, item);
                    }
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
            return InnHtml(HtmlDoc);
        }

        /// <summary>
        /// 替换Html节点  <!-- 请注意：htmldoc必须为同一个，如果你创建了AB两个HTMLDOC，用B的元素在A中替换是不会成功的 -->
        /// </summary>
        /// <param name="HtmlDoc"></param>
        /// <param name="NewNode"></param>
        /// <param name="OldNode"></param>
        private static string ReplaceNode(HtmlDocument HtmlDoc, HtmlNode NewNode, HtmlNode OldNode)
        {
            try
            {
                if (OldNode != null && OldNode.ParentNode != null)
                    OldNode.ParentNode.ReplaceChild(NewNode, OldNode);
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
            return InnHtml(HtmlDoc);
        }

        /// <summary>
        ///  获取Attributes的数据
        /// </summary>
        /// <param name="HtmlCode"></param>
        /// <param name="AttributesName"></param>
        /// <param name="Xpath"></param>
        /// <returns></returns>
        public static List<string> GetAttributesVlaueList(string HtmlCode, string AttributesName, string Xpath)
        {
            List<string> ValueList = new List<string>();
            HtmlNodeCollection htmlNodeCollection = SelectNodes(HtmlCode, Xpath);

            if (htmlNodeCollection != null)
                foreach (HtmlNode SingleNode in htmlNodeCollection)
                {
                    try
                    {
                        string Value = GetAttributesVlaue(SingleNode, AttributesName);
                        if (Value != "")
                            ValueList.Add(Value);
                    }
                    catch (Exception ex)
                    {
                        PrintLog.Log(ex);
                        PrintLog.Log("获取GetAttributesVlaueList错误");
                    }
                }
            else Console.WriteLine("使用XPTH{0},选择{1}，未能获取到数据", Xpath, AttributesName);
            return ValueList;
        }

        /// <summary>
        /// 删除Attributes
        /// </summary>
        /// <param name="SingleNode"></param>
        /// <param name="AttributesName"></param>
        /// <returns></returns>
        private static void AttributesRemove(HtmlNode SingleNode, string AttributesName)
        {
            try
            {
                SingleNode.Attributes[AttributesName].Remove();
            }
            catch (Exception ex)
            {
                if (ex.Message.IndexOf("System.NullReferenceException") == 0)
                    PrintLog.Log($"属性{AttributesName}找不到，空指针异常。\r\n代码：{SingleNode.InnerHtml}");
                else
                    PrintLog.Log(ex);
            }
        }

        /// <summary>
        /// 获取AttributesVlaue
        /// </summary>
        /// <param name="SingleNode"></param>
        /// <param name="AttributesName"></param>
        /// <returns></returns>
        private static string GetAttributesVlaue(HtmlNode SingleNode, string AttributesName)
        {
            try
            {
                return SingleNode.Attributes[AttributesName].Value;
            }
            catch (Exception ex)
            {
                if (ex.ToString().IndexOf("System.NullReferenceException") == 0)
                    PrintLog.Log($"属性{AttributesName}找不到，空指针异常。\r\n代码：{SingleNode.InnerHtml}");
                else
                    PrintLog.Log(ex);
            }
            return "";
        }

        /// <summary>
        /// 输出TEXT
        /// </summary>
        /// <param name="htmlDocument"></param>
        /// <returns></returns>
        public static string InnText(HtmlDocument htmlDocument)
        {
            try
            {
                return htmlDocument.DocumentNode.InnerText;
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
            return "";
        }

        /// <summary>
        /// 输出HTML
        /// </summary>
        /// <param name="htmlDocument"></param>
        /// <returns></returns>
        public static string InnHtml(HtmlDocument htmlDocument)
        {
            try
            {
                return htmlDocument.DocumentNode.InnerHtml;
            }
            catch (Exception ex)
            {
                PrintLog.Log(ex);
            }
            return "";
        }
    }
}